pub struct Rc4 {
    i: u8,
    j: u8,
    state: [u8; 256]
}

impl Rc4 {
    
    ///Key-scheduling algorithm 
    pub fn ksa(key: &[u8]) -> Rc4 {
        //Check if key length is sufficent
        assert!(key.len() >= 1 && key.len() <= 256);
        let mut rc4 = Rc4 { i: 0, j: 0, state: [0; 256] };
        
        for i in 0..256 {
            rc4.state[i] = i as u8;
        }

        for i in 0..256 {
            rc4.j = rc4.j.wrapping_add(rc4.state[i]).wrapping_add(key[i % key.len()]);
            rc4.state.swap(i, rc4.j as usize);
        }

        //Both i and j should be 0 when prga is called 1st time
        rc4.j = 0;

        rc4
    }

    ///Pseudo-random generation algorithm
    fn prga(&mut self) -> u8 {
        self.i = self.i.wrapping_add(1u8);
        self.j = self.j.wrapping_add(self.state[self.i as usize]);
        self.state.swap(self.i as usize, self.j as usize);
        self.state[self.state[self.i as usize].wrapping_add(self.state[self.j as usize]) as usize]
    }

    ///Apply Rc4 to given input slice
    pub fn apply(&mut self, input: &[u8], output: &mut [u8]) {
        assert!(input.len() == output.len());
        for (i, x) in input.iter().enumerate() {
            output[i] = self.prga() ^ *x;
        }
    }
}


pub fn encrypt() {
    let key = "abcefg1234567890".as_bytes();

    // rc4 encrypt
    let mut rc4 = Rc4::ksa(key);
    let text = "2000.00".as_bytes();
    let mut output = vec![0; text.len()];
    rc4.apply(
        text, &mut output
    );
    let en = hex::encode(output).to_string();
    println!("{}", en);

    // base64
    let b = base64::encode_config(en, base64::URL_SAFE);
    println!("{}", b);

    // rc4 decrypt
    let mut rc4 = Rc4::ksa(key);
    let text = hex::decode("9fc877916224a8").unwrap();
    let mut output = vec![0; text.len()];
    rc4.apply(
        &text, &mut output
    );
    let de = std::str::from_utf8(&output).unwrap().to_string();
    println!("{}", de);
}